import { Service } from "egg";
import { Types } from "mongoose";
import { WarehouseModelProps } from "../model/Warehouse";
import { DrugProps } from "../model/Drug";
import { WarehouseRecordProps } from "../model/WarehouseRecord";
import { IndexCondition } from "../common";
import { pick } from "lodash";

export default class WarehouseService extends Service {
  /**
   * 根据传入名称查询
   * @param { [key: string]: any } condition 查询条件
   */
  public findByOne(condition: { [key: string]: any }) {
    return this.ctx.model.Warehouse.findOne(condition).lean();
  }

  /**
   * 查找列表
   */
  public async findList(condition: IndexCondition) {
    const { ctx } = this;
    const { select, pageSize, pageIndex, find } = condition;
    const skip = pageIndex && pageSize ? pageIndex * pageSize : 0;
    const res = await ctx.model.Warehouse.find(find ? find : {})
      .select(select) // 筛选字段（_id不能筛选）
      .skip(skip) // 分页
      .limit(typeof pageSize === "number" ? pageSize : 10) // 一次差多少条
      // .sort(customSort) // 排序
      .lean();
    const count = await ctx.model.Warehouse.find(find ? find : {}).count();
    return {
      count,
      list: res,
      pageSize,
      pageIndex: pageIndex !== undefined && pageIndex + 1,
    };
  }

  /**
   * 入库
   * @param { [key: string]: any } data 测试数据
   * @param {DrugProps} drug 药品信息
   */
  public async add(data: { [key: string]: any }, drug: DrugProps) {
    const { ctx, app } = this;
    let _warehouse;
    const { user: userInfo } = ctx.state;
    const _session = await app.mongoose.startSession();
    _session.startTransaction();
    const {
      amount,
      productionDate,
      expirationDate,
      batches,
      drug_name,
      price,
      entryPrice,
      brand_name,
      standard,
      supply_name,
      business_name,
    } = data;
    // 第七步：添加操作记录
    try {
      // 第六步：入库
      _warehouse = await ctx.model.Warehouse.findOneAndUpdate(
        {
          "drug._id": drug._id,
          "flow.0": business_name,
          flow: { $size: 1 },
          business: business_name,
          batches,
        },
        { $inc: { amount } },
        { session: _session, new: true }
      ).lean();
      if (!_warehouse) {
        const _warehouseArr = await ctx.model.Warehouse.create(
          [
            {
              company_id: Types.ObjectId(ctx.state.user.company),
              drug: {
                _id: drug._id,
                name: drug_name,
                brand: brand_name,
                standard,
                price,
                entryPrice,
                factory: supply_name,
              },
              productionDate,
              expirationDate,
              business: business_name,
              amount,
              batches,
              flow: [business_name],
            },
          ],
          {
            session: _session,
            new: true,
          }
        );
        _warehouse = _warehouseArr[0];
      }
      // 添加入库操作记录
      const _recordInfo = {
        company_id: userInfo.company,
        warehouse: {
          _id: _warehouse._id,
          drug: _warehouse.drug,
          productionDate,
          expirationDate,
          business: business_name,
          amount: _warehouse.amount,
          batches,
          flow: _warehouse.flow,
        },
        output_name: supply_name,
        receive_name: business_name,
        amount,
        level: _warehouse.flow.length,
        type: "入库",
        operate_msg: {
          name: userInfo.name,
          message: `${userInfo.name}进行了一次入库操作！`,
          level: 2,
        },
      };
      await ctx.model.WarehouseRecord.create([_recordInfo], {
        session: _session,
        new: true,
      });
      // 添加库存记录
      const _recordWare = {
        company_id: userInfo.company,
        warehouse: _warehouse._id,
        amount,
      };
      await ctx.model.WarehouseStock.create([_recordWare], {
        session: _session,
        new: true,
      });
    } catch (e) {
      await _session.abortTransaction();
      _session.endSession();
      return null;
    }
    await _session.commitTransaction();
    _session.endSession();
    return _warehouse;
  }

  /**
   * 调拨
   * @param {[key: string]: any} data  调拨
   * @param {WarehouseModelProps} warehouse 库存
   */
  public async transfer(
    data: { [key: string]: any },
    warehouse: WarehouseModelProps
  ) {
    const { ctx } = this;
    const { id, business_name, amount } = data;
    const _session = await ctx.model.Warehouse.startSession();
    _session.startTransaction();
    const { user: userInfo } = ctx.state;
    let _nowWarehouse;
    try {
      // 【1】修改当前库存，减掉对应库存数
      const _prevWarehouse = await ctx.model.Warehouse.findOneAndUpdate(
        { _id: id },
        { $inc: { amount: -amount } },
        { session: _session, new: true }
      ).lean();
      if (!_prevWarehouse) return null;
      // 【2】新增或修改调拨库存
      let _flow: Array<string> = warehouse.flow;
      // 判断当前传进来的商业公司是否已经存在于药品流向中，在就截断数据，不在就推送数据
      if (_flow.includes(business_name)) {
        _flow = _flow.slice(0, _flow.indexOf(business_name) + 1);
      } else {
        _flow.push(business_name);
      }
      _nowWarehouse = await ctx.model.Warehouse.findOneAndUpdate(
        {
          "drug._id": _prevWarehouse.drug._id,
          flow: _flow,
          business: business_name,
          batches: _prevWarehouse.batches,
        },
        {
          $set: { business: business_name, flow: _flow },
          $inc: { amount: +amount },
        },
        { session: _session, new: true }
      ).lean();
      if (!_nowWarehouse) {
        const _warehouseData = pick(
          {
            ...{
              ..._prevWarehouse,
              flow: _flow,
              amount,
              business: business_name,
            },
          },
          [
            "flow",
            "company_id",
            "drug",
            "productionDate",
            "expirationDate",
            "amount",
            "business",
            "batches",
          ]
        );
        const _warehouseArr = await ctx.model.Warehouse.create(
          [_warehouseData],
          {
            session: _session,
            new: true,
          }
        );
        _nowWarehouse = _warehouseArr[0];
      }
      // 第七步：添加操作记录
      const _nowRecord = {
        company_id: userInfo.company,
        warehouse: pick(_nowWarehouse, [
          "_id",
          "drug",
          "productionDate",
          "expirationDate",
          "business",
          "amount",
          "batches",
          "flow",
        ]),
        output_name: _prevWarehouse.business,
        receive_name: business_name,
        amount,
        level: _nowWarehouse.flow.length,
        type: "调拨",
        operate_msg: {
          name: userInfo.name,
          message: `${userInfo.name}对【${business_name}】进行了一次调拨入库操作！`,
          level: 2,
        },
      };
      const _prevRecord = {
        company_id: userInfo.company,
        warehouse: pick(_prevWarehouse, [
          "_id",
          "drug",
          "productionDate",
          "expirationDate",
          "business",
          "amount",
          "batches",
          "flow",
        ]),
        output_name: _prevWarehouse.drug.factory,
        receive_name: _prevWarehouse.business,
        amount,
        level: _nowWarehouse.flow.length,
        type: "入库",
        operate_msg: {
          name: userInfo.name,
          message: `${userInfo.name}对【${business_name}】进行了一次调拨出库操作！`,
          level: 2,
        },
      };
      await ctx.model.WarehouseRecord.create([_nowRecord, _prevRecord], {
        session: _session,
        new: true,
      });
    } catch (e) {
      await _session.abortTransaction();
      _session.endSession();
      return null;
    }
    await _session.commitTransaction();
    _session.endSession();
    return _nowWarehouse;
    // 给新商业公司（也既是仓库）添加或者修改数据
  }

  /**
   * 出库
   * @param data { [key: string]: any } 参数
   */
  public async outWare(data: { [key: string]: any }) {
    const { ctx } = this;
    const { id, hospital_name, amount } = data;
    // 开启事务
    const _session = await ctx.model.Warehouse.startSession();
    _session.startTransaction();
    const { user: userInfo } = ctx.state;
    try {
      // 修改当前库存，减掉对应库存数
      const _warehouse = await ctx.model.Warehouse.findOneAndUpdate(
        { _id: id },
        {
          $inc: { amount: -amount },
        },
        { session: _session, new: true }
      ).lean();
      // 出库并修改库存
      const _record = {
        company_id: userInfo.company,
        warehouse: pick(_warehouse, [
          "_id",
          "drug",
          "productionDate",
          "expirationDate",
          "business",
          "amount",
          "batches",
          "flow",
        ]),
        output_name: _warehouse && _warehouse.business,
        receive_name: hospital_name,
        amount,
        level: _warehouse && _warehouse.flow.length,
        type: "出库",
        operate_msg: {
          name: userInfo.name,
          message: `${userInfo.name}进行了一次出库操作！`,
          level: 2,
        },
      };
      await ctx.model.WarehouseRecord.create([_record], {
        session: _session,
        new: true,
      });
      // 插入出库操作记录
      await _session.commitTransaction();
      _session.endSession();
      return _warehouse;
    } catch (e) {
      // 事务回退
      await _session.abortTransaction();
      _session.endSession();
    }
  }

  /**
   * 退货
   * @param {WarehouseRecordProps} data 参数
   */
  public async recede(data: WarehouseRecordProps) {
    const { ctx } = this;
    // 开启事务
    const _session = await ctx.model.Warehouse.startSession();
    _session.startTransaction();
    const { user: userInfo } = ctx.state;
    try {
      // 对库存记录进行修改
      const _warehouse = await ctx.model.Warehouse.findOneAndUpdate(
        { _id: data.warehouse._id },
        {
          $inc: { amount: +data.amount },
        },
        { session: _session, new: true }
      ).lean();
      // 删除当前操作记录
      await ctx.model.WarehouseRecord.deleteOne(
        { _id: data._id },
        { session: _session, new: true }
      );
      // 插入出库操作记录
      const _record = {
        company_id: userInfo.company,
        warehouse: pick(_warehouse, [
          "_id",
          "drug",
          "productionDate",
          "expirationDate",
          "business",
          "amount",
          "batches",
          "flow",
        ]),
        output_name: data.amount,
        receive_name: data.receive_name,
        amount: data.amount,
        level: _warehouse && _warehouse.flow.length,
        type: "回退",
        operate_msg: {
          name: userInfo.name,
          message: `${userInfo.name}进行了一次出库操作！`,
          level: 2,
        },
      };
      await ctx.model.WarehouseRecord.create([_record], {
        session: _session,
        new: true,
      });
      await _session.commitTransaction();
      _session.endSession();
      return _warehouse;
    } catch (e) {
      await _session.abortTransaction();
      _session.endSession();
    }
  }

  /**
   * 查询库存操作列表
   * @param {IndexCondition} condition 查询参数
   */
  public async getRecordList(condition: IndexCondition) {
    const { ctx } = this;
    const { select, pageSize, pageIndex, find } = condition;
    const skip = pageIndex && pageSize ? pageIndex * pageSize : 0;
    const res = await ctx.model.WarehouseRecord.find(find ? find : {})
      .select(select) // 筛选字段（_id不能筛选）
      .skip(skip) // 分页
      .limit(typeof pageSize === "number" ? pageSize : 0) // 分页
      // .sort(customSort) // 排序
      .lean();
    const count = await ctx.model.WarehouseRecord.find(
      find ? find : {}
    ).count();
    return {
      count,
      list: res,
      pageSize,
      pageIndex: pageIndex !== undefined && pageIndex + 1,
    };
  }
}
